/*
 * @Author: linzeqin
 * @Date: 2019-09-30 09:07:07
 * @description: 沙箱资源调度service
 */
import { Service } from 'egg';
import { PageModel } from '../model/responseModel';
import { ISandboxDispatchReportModel, SandboxDispatchReport } from '../model/sandboxDispatchReport';
import { ISandboxReportModel, SandboxReport } from '../model/sandboxReport';

export default class SandboxService extends Service {
    /**
     * 查询项目列表
     * @param {number} [pageIndex=1]
     * @param {number} [pageSize=10]
     * @returns {Promise<ISandboxReportModel[]>}
     * @memberof SandboxService
     */
    public async queryList(params: {
        /** 当前页 */
        pageIndex: number,
        /** 每页条数 */
        pageSize: number,
        /** 名称 */
        name: string,
        /** 创建时间区间 */
        createTime: [string, string],
        /** 修改时间区间 */
        updateTime: [string, string],
    }): Promise<PageModel<ISandboxReportModel>> {
        try {
            const list: ISandboxReportModel[] = await this.ctx.model.SandboxReport.aggregate([
                {
                    $match: {
                        ...params.name.trim() && { name: { $regex: params.name } },
                        ...params.createTime.length && {
                            createTime: {
                                $gt: new Date(params.createTime[0]).getTime(),
                                $lt: new Date(params.createTime[1]).getTime() + 86400000,
                            },
                        },
                        ...params.updateTime.length && {
                            updateTime: {
                                $gt: new Date(params.updateTime[0]).getTime(),
                                $lt: new Date(params.updateTime[1]).getTime() + 86400000,
                            },
                        },
                    },
                },
                {
                    $sort: {
                        updateTime: -1,
                    },
                },
                {
                    $skip: (params.pageIndex - 1) * params.pageSize,
                },
                {
                    $limit: params.pageSize,
                },
                {
                    $lookup: {
                        from: 'sandbox_dispatch_reports',
                        localField: '_id',
                        foreignField: 'productId',
                        as: 'dispatchList',
                    },
                },
                {
                    $project: {
                        __v: 0,
                    },
                },
            ]);
            const total: number = await this.ctx.model.SandboxReport.countDocuments();
            return new PageModel<ISandboxReportModel>({
                list,
                pageIndex: params.pageIndex || 1,
                pageSize: params.pageSize || 10,
                total,
            });
        } catch (error) {
            this.logger.error(error);
            throw error;
        }
    }

    /**
     * 根据id查看项目详情
     * @memberof SandboxService
     */
    public async detail(id: string) {
        try {
            return await this.ctx.model.SandboxReport.findById(id);
        } catch (error) {
            this.logger.error(error);
            throw error;
        }
    }

    /**
     * 新增or修改
     * @memberof SandboxService
     */
    public async createOrModify(params: Partial<SandboxReport> & {id?: string}) {
        /** 项目名称唯一性校验 */
        if (await this.ctx.model.SandboxReport.findOne({
            name: params.name,
            _id: { $ne: params.id },
        })) {
            throw '项目名称已存在';
        }
        /** 项目名称非空校验 */
        if (params.name === void 0 || params.name == null || params.name.trim() === '') {
            throw '项目名称不能为空';
        }
        if (!params.id) {
            /** 新增 */
            try {
                return await this.ctx.model.SandboxReport.create({
                    ...params,
                } as SandboxReport);
            } catch (error) {
                this.logger.error(error);
                throw error;
            }
        } else {
            /** 修改 */
            try {
                const res = await this.ctx.model.SandboxReport.findByIdAndUpdate(params.id, {
                    ...params,
                });
                if (res) {
                    return await this.ctx.model.SandboxReport.findById(params.id);
                }
            } catch (error) {
                this.logger.error(error);
                throw error;
            }
        }
    }

    /**
     * 删除
     * @memberof SandboxService
     */
    public async delete(id: string) {
        try {
            if (await this.ctx.model.SandboxDispatchReport.findOne({ productId: id })) {
                throw '项目已关联调度，请先解除调度关系';
            }
            return await this.ctx.model.SandboxReport.findByIdAndDelete(id);
        } catch (error) {
            this.logger.error(error);
            throw error;
        }
    }

    /** 查询调度列表 */
    public async dispatchList(params: {
        /** 当前页 */
        pageIndex: number,
        /** 每页条数 */
        pageSize: number,
        /** 关联的项目名称 */
        name: string,
        /** 创建时间区间 */
        createTime: [string, string],
        /** 修改时间区间 */
        updateTime: [string, string],
    }): Promise<any> {
        try {
            const list: ISandboxDispatchReportModel[] = await this.ctx.model.SandboxDispatchReport.aggregate([
                {
                    $match: {
                        ...params.createTime && params.createTime.length && {
                            createTime: {
                                $gt: new Date(params.createTime[0]).getTime(),
                                $lt: new Date(params.createTime[1]).getTime() + 86400000,
                            },
                        },
                        ...params.updateTime && params.updateTime.length && {
                            updateTime: {
                                $gt: new Date(params.updateTime[0]).getTime(),
                                $lt: new Date(params.updateTime[1]).getTime() + 86400000,
                            },
                        },
                    },
                },
                {
                    $lookup: {
                        from: 'sandbox_reports',
                        localField: 'productId',
                        foreignField: '_id',
                        as: 'product',
                    },
                },
                {
                    $match : {
                        ...params.name.trim() && { 'product.name': { $regex: params.name } },
                    },
                },
                {
                    $sort: {
                        dispatchNo: -1,
                    },
                },
                {
                    $skip: (params.pageIndex - 1) * params.pageSize,
                },
                {
                    $limit: params.pageSize,
                },
                {
                    $unwind: {
                        path: '$product',
                        preserveNullAndEmptyArrays: true,
                    },
                },
                {
                    $project: {
                        __v: 0,
                    },
                },
            ]);
            const total: number = await this.ctx.model.SandboxDispatchReport.countDocuments();

            return new PageModel<ISandboxDispatchReportModel>({
                list,
                pageIndex: params.pageIndex || 1,
                pageSize: params.pageSize || 10,
                total,
            });
        } catch (error) {
            this.logger.error(error);
            throw error;
        }
    }

    /**
     * 根据id查询调度项目详情
     * @memberof SandboxService
     */
    public async dispatchDetail(id: string) {
        try {
            return await this.ctx.model.SandboxDispatchReport.findById(id);
        } catch (error) {
            this.logger.error(error);
            throw error;
        }
    }
    /**
     * 新增或修改调度
     * @memberof SandboxService
     */
    public async dispatchCreateOrModify(params: Partial<SandboxDispatchReport> & {id?: string}) {
        if (!params.id) {
            /** 新增 */
            try {
                const res = await this.ctx.model.SandboxDispatchReport.find({}, {}, {
                    limit: 1,
                    sort: {
                        createTime: -1,
                    },
                });
                return await this.ctx.model.SandboxDispatchReport.create({
                    ...params,
                    dispatchNo: res && res[0].dispatchNo + 1 || 1,
                } as SandboxDispatchReport);
            } catch (error) {
                this.logger.error(error);
                throw error;
            }
        } else {
            /** 修改 */
            try {
                return await this.ctx.model.SandboxDispatchReport.findByIdAndUpdate(params.id, {
                    ...params,
                });
            } catch (error) {
                this.logger.error(error);
                throw error;
            }
        }
    }

    /**
     * 删除调度
     * @memberof SandboxService
     */
    public async dispatchDelete(id: string) {
        try {
            return await this.ctx.model.SandboxDispatchReport.findByIdAndDelete(id);
        } catch (error) {
            this.logger.error(error);
            throw error;
        }
    }

    /**
     * 根据调度序号和环境变量获取脚本内容
     * @memberof SandboxService
     */
    public async getScript(dpNo: number, env: string) {
        try {
            return await this.ctx.model.SandboxDispatchReport.aggregate([
                {
                    $match: {
                        dispatchNo: dpNo,
                    },
                },
                {
                    $lookup: {
                        from: 'sandbox_reports',
                        localField: 'productId',
                        foreignField: '_id',
                        as: 'product',
                    },
                },
                {
                    $unwind: {
                        path: '$product',
                    },
                },
                {
                    $unwind: {
                        path: '$product.scriptList',
                    },
                },
                {
                    $match: {
                        'product.scriptList.env': env,
                    },
                },
            ]);
        } catch (error) {
            this.logger.error(error);
            throw error;
        }
    }
}
